package parser;

import java.util.LinkedHashMap;
import java.util.TreeSet;

public class Symboltable {

    private TreeSet<Integer> addressSpace;
    private LinkedHashMap<String, Symbol> table;

    public Symboltable() {
        this.table = new LinkedHashMap<String, Symbol>();
        this.addressSpace = new TreeSet<>();
    }

    public void insert(final String key, final BTypes type) {
        this.table.put(key, new Symbol(type, getNextFree()));
        increaseNextFree();
    }

    public boolean is_in(final String key) {
        return this.table.containsKey(key);
    }

    public BTypes type_of(final String key) {
        return this.table.get(key).getType();
    }

    public int getRegister(final String key) {
        return this.table.get(key).getRegister();
    }

    public int getNextFree() {
        if (this.addressSpace.isEmpty()) {
            return 0;
        } else {
            for (int i = 0; i < this.addressSpace.last(); i++) {
                if (!this.addressSpace.contains(i)) {
                    return i;
                }
            }
            return this.addressSpace.last() + 1;
        }
    }

    public void increaseNextFree() {
        if (this.addressSpace.isEmpty()) {
            this.addressSpace.add(0);
        } else {
            for (int i = 0; i < this.addressSpace.last(); i++) {
                if (!this.addressSpace.contains(i)) {
                    this.addressSpace.add(i);
                    return;
                }
            }
            this.addressSpace.add(this.addressSpace.last() + 1);
        }
    }

    public void free(final int address) {
        this.addressSpace.remove(address);
    }

    private class Symbol {

        private final BTypes type;
        private final int register;

        private Symbol(final BTypes type, final int register) {
            this.type = type;
            this.register = register;
        }

        private BTypes getType() {
            return this.type;
        }

        private int getRegister() {
            return this.register;
        }
    }
}

